#ifndef GEOMETRY_H
#define GEOMETRY_H

#include "Model.h"

#include <QList>

namespace Model {
    
/**
 * Represents a single point, intersection between walls.
 */
class Vertex {
    friend class boost::serialization::access;
    
public:
    /**
     * Constructs a vertex at coordinates (0,0)
     */
    Vertex();
    
    /**
     * Constructs a vertex at coordinates (x,y)
     * \param x X coordinate
     * \param y Y coordinate
     */
    Vertex(double x, double y);
    
    void move(double x, double y); ///< Moves the vertex to coordinates (x,y)
    double x() const; ///< Returns the X coordinate
    double y() const; ///< Returns the Y coordinate
    bool isNear(double x, double y); ///< Checks whethers the Vertex is near the point (x,y)
    
    static void align(QList<Vertex*>); ///< Unimplemented
    
protected:
    double _x;
    double _y;
    
private:
    template<class Archive> 
    void serialize(Archive &ar, const unsigned int version) 
    {
        ar & NVP(_x) & NVP(_y);
    }
};

/**
 * Represents a line between two Vertexes. This class will be mapped into a wall
 * by the map loader.
 */
class Edge {
    friend class boost::serialization::access;
    
public:
    /**
     * Constructs an edge going from the start point to the end point.
     * \param start Start point
     * \param end End point
     */
    Edge(Vertex *start, Vertex *end);
    
    const Vertex *start() const; ///< The start point.
    const Vertex *end() const;   ///< The end point.
    
    bool hasEnd(Vertex* v) const;    ///< Returns true if the start or the end is equal to v
    bool isNear(double x, double y); ///< Returns true if the point (x,y) is near the edge
    
    /**
     * Cuts the edge in two parts.
     * \param source Initial edge to cut.
     * \param x The X coordinate of the cut point.
     * \param y The Y coordinate of the cut point.
     * \param first Pointer to the location where the first edge reference will be located.
     * \param second Pointer to the location where the second edge reference will be located.
     * \param cutpoint Pointer to the location where the newly created edge will be located.
     */
    static void cut(Edge *source, double x, double y, Edge **first, Edge **second, Vertex **cutpoint);
    
protected:
    Edge();
    Vertex *_start;
    Vertex *_end;
    
private:
    template<class Archive> 
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & NVP(_start) & NVP(_end);
    }
};

/**
 * Represents a set of Vertexes and Edges.
 */
class Mesh {  
public:
    /**
     * Constructs a new empty mesh.
     */
    Mesh();
    
    /**
     * Returns a reference to the list of vertexes.
     */
    QList<Vertex*> *vertexes();
    /**
     * Returns a reference to the list of edges.
     */
    QList<Model::Edge*> *edges();
    
protected:
    QList<Vertex*> _vertexes;
    QList<Model::Edge*> _edges;
    
private:
    friend class boost::serialization::access;
    template<class Archive>
    void save(Archive & ar, const unsigned int version) const
    {
        std::list<Vertex*> vertexes = _vertexes.toStdList();
        std::list<Model::Edge*> edges = _edges.toStdList();
        ar & NVP(vertexes) & NVP(edges);
    }
    template<class Archive>
    void load(Archive & ar, const unsigned int version)
    {
        std::list<Vertex*> vertexes;
        std::list<Model::Edge*> edges;
        ar & NVP(vertexes) & NVP(edges);
        _vertexes = QList<Vertex*>::fromStdList(vertexes);
        _edges = QList<Model::Edge*>::fromStdList(edges);
    }
    BOOST_SERIALIZATION_SPLIT_MEMBER()
};

} // namespace Geometry

#endif
